# @Time : 2025-01-02 17:06
# @Author : Fioman 
# @Phone : 13149920693
"""
发送消息到web的封装,将封装的消息内容放到和web通信的队列中去,然后队列循环的任务,会发送
对应消息到前端,这里的消息封装和前端要一一对应起来.
"""
import base64
import json
from io import BytesIO
from typing import Dict

import cv2 as cv
from PIL import Image

from app.device_state import DeviceState
from app_config import webMsgQueue
from common.produce_logger import debug_produce
from db_tool.db_config import TableName
from db_tool.db_handler import DbHandler
from params.camera_params import CameraParams
from personal_tool.data_result import DataResult
from web_tool.modal_config import NotificationConfig
from web_tool.produce_data_model import ProduceDataType
from web_tool.tool_data_model import EapDataType, ToolDataType

db = DbHandler()
cp = CameraParams()


def image_to_string(image):
    """
    将一幅图转换成字符串的格式,可以发送给前端的那种字符串类型
    :param image:要转换的图片,可以是彩色的,也可以是灰度图
    :return: 返回图像的字符串格式,可以让前端进行显示
    """
    clone = image.copy()
    pilImg = Image.fromarray(clone)
    buffer = BytesIO()
    pilImg.save(buffer, format="JPEG")
    imageStr = base64.b64encode(buffer.getvalue()).decode('utf-8')
    return imageStr


def send_msg_to_web(msgType, data: Dict):
    """
    封装消息到前端,第一个参数是消息的类型,第二个是消息的内容
    :param msgType:
    :param data: 以字典的形式返回给前端数据,字典的键需要和前端的要更新的数据保持一致,这个怎么保证呢
                           只能认为的去约束了,编写代码的时候先写前端,后写后端
    :return:
    """
    webMsgQueue.put(json.dumps({msgType: data}))


def show_modal_in_web(modalConfig: dict):
    """
    发送弹窗配置到前端
    :param modalConfig: 弹窗配置,这个配置要和前端的参数相对应
    """
    msgType = "ShowModal"
    send_msg_to_web(msgType, modalConfig)


def show_notification_in_web(title: str, content: str, visible: bool = True):
    """
    显示通知弹窗
    """
    NotificationConfig["content"] = content
    NotificationConfig["title"] = title
    NotificationConfig["visible"] = visible
    show_modal_in_web(NotificationConfig)


def show_error_info_in_web(error_info: str):
    """
    显示错误信息弹窗
    """
    modal_config = {
        "type": "ERROR_INFO",
        "title": "错误提示",
        "errorInfo": error_info,
        "visible": True
    }
    show_modal_in_web(modal_config)


def update_device_state_in_web(deviceState: DeviceState):
    """
    更新设备状态到前端
    """
    send_msg_to_web("UpdateDeviceState", deviceState.to_dict())


def show_not_first_cutline_in_web(cutLineRes, calcSize, calcError, cutBoardSize,
                                  catchCenter01, catchCenter02):
    """
    显示非首件的切割线信息,图像,尺寸还有计算误差,抓取中心坐标1和抓取中心坐标2
    """
    maxSize = 350
    h, w = cutLineRes.shape[:2]
    if h > w:
        newHeight = maxSize
        newWidth = int((w / h) * newHeight)
    else:
        newWidth = maxSize
        newHeight = int((h / w) * newWidth)
    imageSend = cv.resize(cutLineRes, (newWidth, newHeight), interpolation=cv.INTER_AREA)
    dataSend = {
        ProduceDataType.notFirstCutLineRes.value: image_to_string(imageSend),
        ProduceDataType.calcSize.value: calcSize,
        ProduceDataType.notFirstImageSize.value: (newWidth, newHeight),
        ProduceDataType.notFirstCutLineSize.value: cutBoardSize,
        ProduceDataType.notFirstCalError.value: calcError,
        ProduceDataType.catchCenter01.value: catchCenter01,
        ProduceDataType.catchCenter02.value: catchCenter02,
    }
    send_msg_to_web("UpdateProduceData", dataSend)


def show_first_cutline_in_web(firstCutLineRes, firstCalError, cutBoardSizeFirst,
                              catchCenter01FirstCut, catchCenter02FirstCut):
    """
    显示首件的信息,图像,尺寸还有计算误差
    """
    maxSize = 350
    h, w = firstCutLineRes.shape[:2]
    if h > w:
        newHeight = maxSize
        newWidth = int((w / h) * newHeight)
    else:
        newWidth = maxSize
        newHeight = int((h / w) * newWidth)
    imageSend = cv.resize(firstCutLineRes, (newWidth, newHeight),
                          interpolation=cv.INTER_AREA)
    dataSend = {
        ProduceDataType.firstCutLineRes.value: image_to_string(imageSend),
        ProduceDataType.firstCutLineSize.value: [newWidth, newHeight],
        ProduceDataType.firstCalError.value: firstCalError,
        ProduceDataType.cutBoardSizeFirst.value: cutBoardSizeFirst,
        ProduceDataType.catchCenter01FirstCut.value: catchCenter01FirstCut,
        ProduceDataType.catchCenter02FirstCut.value: catchCenter02FirstCut,
    }
    send_msg_to_web("UpdateProduceData", dataSend)


def show_cutline_in_web(cutlineRes, info):
    """
    显示切割线检查的弹窗
    """
    maxSize = 600
    h, w = cutlineRes.shape[:2]
    if h > w:
        newHeight = maxSize
        newWidth = int((w / h) * newHeight)
    else:
        newWidth = maxSize
        newHeight = int((h / w) * newWidth)
    imageSend = cv.resize(cutlineRes, (newWidth, newHeight), cv.INTER_AREA)
    dataSend = {
        ProduceDataType.cutLineImageData.value: image_to_string(imageSend),
        ProduceDataType.cutLineModalVisible.value: True,
        ProduceDataType.calcResInfo.value: info,
    }
    send_msg_to_web("UpdateProduceData", dataSend)


def show_totalboard_error_in_web(totalboardRes, info):
    """
    这里的图片要进行缩放,至于缩放的比例,是按照宽度是1000
    :param totalboardRes:
    :param info:
    :return:
    """
    maxSize = 600
    h, w = totalboardRes.shape[:2]
    if h > w:
        newHeight = maxSize
        newWidth = int((w / h) * newHeight)
    else:
        newWidth = maxSize
        newHeight = int((h / w) * newWidth)
    imageSend = cv.resize(totalboardRes, (newWidth, newHeight), cv.INTER_AREA)
    dataSend = {
        ProduceDataType.totalBoardImageData.value: image_to_string(imageSend),
        ProduceDataType.totalboardErrorModalVisible.value: True,
        ProduceDataType.totalBoardErrorInfo.value: info,
    }
    send_msg_to_web("UpdateProduceData", dataSend)


def show_inner_board_hand_1pin(image, labelSizePix, labelSizeMm):
    """
    显示内板手动的弹窗2拼板
    """
    h, w = image.shape[:2]
    newWidth, newHeight = int(w / cp.sizeScale), int(h / cp.sizeScale)
    imageSend = cv.resize(image, (newWidth, newHeight), cv.INTER_AREA)
    dataSend = {
        ProduceDataType.handSingleBoxSrc.value: image_to_string(imageSend),
        ProduceDataType.handSingleBoxVisible.value: True,
        ProduceDataType.labelSingleBoxSizeMm.value: labelSizeMm,
        ProduceDataType.labelSingleBoxSizePix.value: labelSizePix,
    }
    send_msg_to_web("UpdateProduceData", dataSend)


def show_inner_board_hand_4pin(image, labelSizePix, labelSizeMm):
    """
    显示内板手动的弹窗
    """
    h, w = image.shape[:2]
    newWidth, newHeight = int(w / cp.sizeScale), int(h / cp.sizeScale)
    imageSend = cv.resize(image, (newWidth, newHeight), cv.INTER_AREA)
    dataSend = {
        ProduceDataType.handSingleBoxSrc.value: image_to_string(imageSend),
        ProduceDataType.handSingleBoxVisible.value: True,
        ProduceDataType.labelSingleBoxSizeMm.value: labelSizeMm,
        ProduceDataType.labelSingleBoxSizePix.value: labelSizePix,
    }
    send_msg_to_web("UpdateProduceData", dataSend)


def show_board_size_hand_label_in_web(image, labelSize, labelSizeMm):
    """
    显示尺寸检查的弹窗
    """
    h, w = image.shape[:2]
    newWidth, newHeight = int(w / cp.sizeScale), int(h / cp.sizeScale)
    imageSend = cv.resize(image, (newWidth, newHeight), cv.INTER_AREA)
    dataSend = {
        ProduceDataType.handLabelImageData.value: image_to_string(imageSend),
        ProduceDataType.handLabelModalVisible.value: True,
        ProduceDataType.handLabelSize.value: labelSize,
        ProduceDataType.labelBoardSizeMm.value: labelSizeMm,
    }
    send_msg_to_web("UpdateProduceData", dataSend)


def update_cim_message_in_web(messageType: str, cim_message: str, showTimeLeft: int, visible: bool):
    """
    显示CIM消息的弹窗
    """
    dataSend = {
        ProduceDataType.cimMessageModalVisible.value: visible,
        ProduceDataType.cimMessageType.value: messageType,
        ProduceDataType.cimMessage.value: cim_message,
        ProduceDataType.showTimeLeft.value: showTimeLeft,  # 显示剩余时间
    }
    send_msg_to_web("UpdateProduceData", dataSend)


def show_board_size_check_in_web(image, boardSize, inputSize, boardCalcError):
    """
    显示尺寸检查的弹窗
    """
    maxSize = 600
    h, w = image.shape[:2]
    if h > w:
        newHeight = maxSize
        newWidth = int((w / h) * newHeight)
    else:
        newWidth = maxSize
        newHeight = int((h / w) * newWidth)
    imageSend = cv.resize(image, (newWidth, newHeight), interpolation=cv.INTER_AREA)
    dataSend = {
        ProduceDataType.sizeCheckImageData.value: image_to_string(imageSend),
        ProduceDataType.sizeCheckModalVisible.value: True,
        ProduceDataType.inputSize.value: inputSize,
        ProduceDataType.boardSize.value: boardSize,
        ProduceDataType.boardCalcError.value: boardCalcError,
    }
    send_msg_to_web("UpdateProduceData", dataSend)


def update_produce_model_in_web(dataType: ProduceDataType, orderKey=None):
    """
    更新produceModel中的属性类型
    :param dataType:发送的消息类型
    :return:
    """
    match dataType:
        case ProduceDataType.workingOrder:
            if orderKey is None:
                ds = DeviceState()
                orderKey = ds.orderUsedKey
            result = db.get_data_one(TableName.orders, query={"key": orderKey})
        case ProduceDataType.totalOrders:
            result = db.get_data_list(TableName.orders)
        case _:
            debug_produce(f"in update_produce_model_in_web() "
                          f"ProduceDataType: {dataType.name} 未处理")
            result = DataResult()
    if result.state:
        data = result.data
    else:
        if dataType == ProduceDataType.workingOrder:
            data = {}
        else:
            data = []
    dataSend = {
        dataType.value: data
    }
    send_msg_to_web("UpdateProduceData", dataSend)


def update_tool_data_in_web(toolDataType: ToolDataType):
    """
    更新toolModel中的数据到前端
    """
    match toolDataType:
        case ToolDataType.cameraParams:
            result = db.get_data_list(TableName.cameraParams, query={"key": "1"})
        case ToolDataType.imageJointParams:
            result = db.get_data_list(TableName.imageJointParams, query={"key": "1"})
        case ToolDataType.robotParams:
            result = db.get_data_list(TableName.robotParams, query={"key": "1"})
        case _:
            debug_produce(f"in update_tool_data_in_web() "
                          f"ToolDataType: {toolDataType.name} 未处理")
            result = DataResult()
    if result.state:
        data = result.data
    else:
        data = []
    dataSend = {
        toolDataType.value: data
    }
    send_msg_to_web("UpdateToolData", dataSend)


def show_device_lock_in_web():
    """
    显示设备锁定的弹窗
    """
    dataSend = {
        ProduceDataType.deviceLockModalVisible.value: True,
    }
    send_msg_to_web("UpdateProduceData", dataSend)


def show_scan_modal_in_web():
    dataSend = {
        ProduceDataType.scanModalVisible.value: True,
        ProduceDataType.scanHintInfo.value: "批次任务已完成,请扫码切换下一单"
    }
    send_msg_to_web("UpdateProduceData", dataSend)


def update_alarm_records_in_web():
    """
    更新报警记录到前端
    """
    alarmRes = db.get_data_list(TableName.alarmRecords,
                                sortName="happenTime", isReverse=True)
    if not alarmRes.state:
        debug_produce(f"in update_alarm_records_in_web() Error:{alarmRes.info} ")
        alarmRecords = []
    else:
        alarmRecords = alarmRes.data
    dataSend = {
        ProduceDataType.alarmRecords.value: alarmRecords,
    }
    send_msg_to_web("UpdateProduceData", dataSend)


def update_eap_orders_in_web():
    """
    更新Eap工单列表到前端
    """
    orderRes = db.get_data_list(TableName.eapOrders, sortName="taskId")
    if not orderRes.state:
        debug_produce(f"in update_eap_orders_in_web() Error:{orderRes.info} ")
        orders = []
    else:
        orders = [item for item in orderRes.data if item.get("taskId", 0) > 0]
    update_eap_data_model_in_web(EapDataType.eapOrders, orders)


def update_eap_data_model_in_web(eapDataType: EapDataType, value):
    dataSend = {
        eapDataType.value: value
    }
    send_msg_to_web("UpdateEapData", dataSend)


if __name__ == '__main__':
    print(123)
